package heap

import "jvm/nzpJvm/classfile"

// 一个Field结构体代表一个运行时字段的直接引用。
// 这个结构体位于方法区。java代码中不能直接访问
// Field结构体被加载到方法区后，可以在堆区生成一个类型为Field类型的java对象
// java代码可以通过访问那个java对象间接访问此结构体
type Field struct {
	ClassMember
	slotId          uint
	constValueIndex uint
}

// 新建一个Field结构体Slice
func newFields(class *Class, cfFields []*classfile.MemberInfo) []*Field {
	fields := make([]*Field, len(cfFields))
	for i, cfField := range cfFields {
		fields[i] = &Field{}
		fields[i].class = class
		// 复制信息
		fields[i].copyMemberInfo(cfField)
		// 复制属性
		fields[i].copyAttributes(cfField)
	}
	return fields
}

func (self *Field) copyAttributes(field *classfile.MemberInfo) {
	// 如果这个字段是常量，获取常量值在常量池中的索引
	if valAttr := field.ConstantValueAttribute(); valAttr != nil {
		self.constValueIndex = uint(valAttr.ConstantValueIndex())
	}
}


// 当前成员能不能被指定的另一个类访问到
func (self *Field) isAccessibleTo(other *Class) bool {
	if self.IsPublic() {
		// 公开的访问权限
		return true
	}
	class := self.class
	if self.IsProtected() {
		// protected访问权限，仅限当前包下，或者其他包的子类访问
		return class == other || other.IsSubClassOf(class) || class.GetPackageName() == other.GetPackageName()
	}
	if !self.IsPrivate() {
		// 默认的访问权限，只允许当前包访问。如果是同一个类，那就一定在同一个包下
		return class.GetPackageName() == other.GetPackageName()
	}
	// 私有的访问权限，仅限当前类访问
	return class == other
}

// 判断字段的Access_Flag
func (self *Field) IsPublic() bool {
	return 0 != self.accessFlags&ACC_PUBLIC
}
func (self *Field) IsPrivate() bool {
	return 0 != self.accessFlags&ACC_PRIVATE
}
func (self *Field) IsProtected() bool {
	return 0 != self.accessFlags&ACC_PROTECTED
}
func (self *Field) IsStatic() bool {
	return 0 != self.accessFlags&ACC_STATIC
}
func (self *Field) IsFinal() bool {
	return 0 != self.accessFlags&ACC_FINAL
}
func (self *Field) IsVolatile() bool {
	return 0 != self.accessFlags&ACC_VOLATILE
}
func (self *Field) IsTransient() bool {
	return 0 != self.accessFlags&ACC_TRANSIENT
}
func (self *Field) IsSynthetic() bool {
	return 0 != self.accessFlags&ACC_SYNTHETIC
}
func (self *Field) IsEnum() bool {
	return 0 != self.accessFlags&ACC_ENUM
}

// get方法
// 是否是long或者double类型
func (self *Field) isLongOrDouble() bool {
	return self.descriptor == "J" || self.descriptor == "D"
}

// 此字段对应的槽位id
func (self *Field) SlotId() uint {
	return self.slotId
}

// 常量值在常量池中的索引
func (self *Field) ConstValueIndex() uint {
	return self.constValueIndex
}
